#pragma once

#include <bits/types/FILE.h>
#include <cstddef>
#include <iostream>
#include <string>
#include<cstdio>
#include<set>
#include<unistd.h>

#include"Log.hpp"

using namespace LogModule;

const int size_line = 1024;
const std::string myshell_path = "./myshell";

class Command
{
public:
    //白名单
    Command()
    {
        _white_list.insert("ls");
        _white_list.insert("pwd");
        _white_list.insert("ls -l");
        _white_list.insert("ll");
        _white_list.insert("touch");
        _white_list.insert("who");
        _white_list.insert("whoami");
    }

    //安全检查
    bool SafeCheck(std::string cmdstr)
    {
        auto iter = _white_list.find(cmdstr);
        return iter == _white_list.end() ? false : true;
    }
    //执行字符串“ls -l”等命令，并返回结果
    std::string Execute(std::string cmdstr)
    {

        //过程：
        //1.创建pipe
        //2.fork + dup2(pipe[1],1) 重定向标准输出到管道中+ exec*,执行结果给父进程，pipe[0]
        //3.return
        
        //version -2,调用自己的myshell.cc实现        
       if(!SafeCheck(cmdstr)) return std::string(cmdstr+"不支持");
       int pipefd[2];
       if(pipe(pipefd) == -1) return std::string("pipe create error");
       
       pid_t pid = fork();
       if(pid == -1)
       {
           ::close(pipefd[0]);
           ::close(pipefd[1]);
           return std::string("fork error");
       }

       if(pid == 0)
       {
           //childern
           ::close(pipefd[0]); //关闭读端
           dup2(pipefd[1],1);  //重定向标准输出到管道写端
           dup2(pipefd[1],2);  //重定向标准错误到管道写端
           
           ::close(pipefd[1]);
            
           if(fork() > 0) exit(0);
           // 构造参数：让myshell执行指定命令后退出
           // 格式为：./myshell "要执行的命令"
           char *args[] = {
               (char *) myshell_path.c_str(),
               (char *) cmdstr.c_str(),
               NULL
           };

           //程序替换
           execv(myshell_path.c_str(),args);

           //走到该处说明程序替换失败
           LOG(LogLevel::FATAL) << "execv failed";
           exit(1);
        }
        else
        {
           //parent
           ::close(pipefd[1]);
           char buffer[size_line];
           std::string result;
           ssize_t  n = 0;
           while((n = ::read(pipefd[0],buffer,sizeof(buffer) - 1)) > 0)
           {
               buffer[n] = '\0';
               result += buffer;
           }
        
           ::close(pipefd[0]);
           return result.empty() ? std::string("Done") : result;

        }
//       //version -1利用popen实现上述步骤，不包含dup操作
//       if(!SafeCheck(cmdstr)) return std::string(cmdstr+"不支持");
//       FILE * fp = ::popen(cmdstr.c_str(),"r");
//       if(fp == nullptr)
//       {
//           return std::string("popen failed");
//       }
//
//       char buffer[size_line];
//       std::string result;
//
//       while(true)
//       {
//           char * ret = ::fgets(buffer,sizeof(buffer),fp);
//           if(!ret) break;
//           result += ret;
//        
//       }
//       ::pclose(fp);
//       return result.empty() ? std::string("Done not") : result;
    }
private:
    //添加白名单，规定可以执行的命令
    std::set<std::string> _white_list;
};
